// 文章生成
package articlegenerate

import (
	"bufio"
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"mime/multipart"
	"net/http"
	"strings"
	"sync"
	"time"

	"github.com/gomarkdown/markdown"
	"github.com/spf13/cast"

	"ErgoGo/internal/model/conf"
	"ErgoGo/pkg/config"
)

// DeepSeek请求结构
type DeepSeekRequest struct {
	Model            string    `json:"model"`
	Messages         []Message `json:"messages"`
	Temperature      float64   `json:"temperature"`
	MaxTokens        int       `json:"max_tokens"`
	Timeout          int       `json:"timeout"`
	Stream           bool      `json:"stream"`
	TopP             float64   `json:"top_p"`
	FrequencyPenalty float64   `json:"frequency_penalty"`
}

type Message struct {
	Role    string `json:"role"`
	Content string `json:"content"`
}

// DeepSeek响应结构
type DeepSeekResponse struct {
	Choices []Choice `json:"choices"`
}

type Choice struct {
	Message Message `json:"message"`
}

// DeepSeek流式响应结构
type DeepSeekStreamResponse struct {
	ID      string `json:"id"`
	Object  string `json:"object"`
	Created int64  `json:"created"`
	Model   string `json:"model"`
	Choices []struct {
		Delta struct {
			Content string `json:"content"`
		} `json:"delta"`
		FinishReason string `json:"finish_reason"`
	} `json:"choices"`
}

// 博客发布请求结构
type Article struct {
	Keywords string `json:"keywords"`
	Title    string `json:"title"`
	Content  string `json:"content"`
	Status   int    `json:"status"`
	Category string `json:"category"`
	TagIds   string `json:"tag_ids"`
}

// 文章生成器
type ArticleGenerator struct {
	httpClient *http.Client
}

func NewArticleGenerator() *ArticleGenerator {
	return &ArticleGenerator{
		httpClient: &http.Client{Timeout: 180 * time.Second},
	}
}

// 从DeepSeek生成内容
func (ag *ArticleGenerator) generateContent(prompt string, wordCount int, isTitle bool) (string, error) {
	// 获取设置中的前缀
	prefix := conf.GetConfig(conf.Prefix)

	// 构建完整的提示词
	fullPrompt := prompt
	if prefix != "" && !isTitle {
		fullPrompt = prefix + "\n\n关键词为：'" + prompt + "'"
	}

	// 根据文章长度设置调整字数
	articleLength := conf.GetConfig(conf.ArticleLength)
	if articleLength != "" && !isTitle {
		switch articleLength {
		case "short":
			wordCount = 750 // 短篇约750字
		case "medium":
			wordCount = 1500 // 中篇约1500字
		case "long":
			wordCount = 2000 // 长篇约2000字
		}
	}

	// 构造请求prompt时添加Markdown格式要求
	formatInstruction := ""
	if !isTitle {
		formatInstruction = `请使用Markdown格式，按以下结构生成文章：
[标题] 
[引言] 
[主体（分3部分）] 
[结论]`
	}

	content := fmt.Sprintf("%s\n%s请生成约%d字的内容，语言流畅。", fullPrompt, formatInstruction, wordCount)
	log.Println("提示词: ", content)

	requestBody := DeepSeekRequest{
		Model: "deepseek-chat",
		Messages: []Message{
			{
				Role:    "user",
				Content: content,
			},
		},
		Temperature:      0.5, // 降低随机性
		MaxTokens:        4000,
		Timeout:          300,
		Stream:           true,
		TopP:             0.9, // 增加多样性
		FrequencyPenalty: 0.2, // 减少重复
	}

	jsonData, err := json.Marshal(requestBody)
	if err != nil {
		return "", fmt.Errorf("marshal request failed: %v", err)
	}

	// 添加重试机制
	maxRetries := 3
	var lastErr error
	for i := 0; i < maxRetries; i++ {
		if i > 0 {
			// 重试前等待一段时间
			time.Sleep(time.Duration(i*2) * time.Second)
			log.Printf("第 %d 次重试生成内容...", i+1)
		}

		req, err := http.NewRequest("POST", "https://api.deepseek.com/v1/chat/completions", bytes.NewBuffer(jsonData))
		if err != nil {
			lastErr = fmt.Errorf("create request failed: %v", err)
			continue
		}
		// 累加api调用次数
		conf.IncrementApiCount()

		req.Header.Set("Authorization", "Bearer "+config.Get("app.deepseek_api_key"))
		req.Header.Set("Content-Type", "application/json")
		req.Header.Set("Accept", "text/event-stream")

		resp, err := ag.httpClient.Do(req)
		if err != nil {
			lastErr = fmt.Errorf("API request failed: %v", err)
			continue
		}
		defer resp.Body.Close()

		if resp.StatusCode != http.StatusOK {
			body, _ := io.ReadAll(resp.Body)
			lastErr = fmt.Errorf("API error: %s", string(body))
			continue
		}

		// 使用bufio.Reader读取流式响应
		reader := bufio.NewReader(resp.Body)
		var fullContent strings.Builder

		for {
			line, err := reader.ReadString('\n')
			if err != nil {
				if err == io.EOF {
					break
				}
				lastErr = fmt.Errorf("read stream failed: %v", err)
				break
			}

			// 跳过空行和"data: "前缀
			line = strings.TrimSpace(line)
			if line == "" || !strings.HasPrefix(line, "data: ") {
				continue
			}

			// 移除"data: "前缀
			line = strings.TrimPrefix(line, "data: ")

			// 检查是否是结束标记
			if line == "[DONE]" {
				break
			}

			// 解析JSON响应
			var streamResp DeepSeekStreamResponse
			if err := json.Unmarshal([]byte(line), &streamResp); err != nil {
				lastErr = fmt.Errorf("parse stream response failed: %v", err)
				continue
			}

			// 提取内容
			if len(streamResp.Choices) > 0 && streamResp.Choices[0].Delta.Content != "" {
				fullContent.WriteString(streamResp.Choices[0].Delta.Content)
			}
		}

		if lastErr != nil {
			continue
		}

		content := fullContent.String()
		if content == "" {
			lastErr = fmt.Errorf("no content generated")
			continue
		}

		return content, nil
	}

	return "", fmt.Errorf("after %d retries, last error: %v", maxRetries, lastErr)
}

func (ag *ArticleGenerator) markdownToHTML(markdownContent string) string {
	// 检查并提取被```markdown和```包裹的内容
	if strings.Contains(markdownContent, "```markdown") && strings.Contains(markdownContent, "```") {
		// 查找```markdown的开始位置
		startIndex := strings.Index(markdownContent, "```markdown") + len("```markdown")
		// 查找对应的```结束位置
		endIndex := strings.Index(markdownContent[startIndex:], "```")
		if endIndex != -1 {
			// 提取被包裹的内容
			markdownContent = markdownContent[startIndex : startIndex+endIndex]
			markdownContent = strings.TrimSpace(markdownContent)
		}
	}
	return string(markdown.ToHTML([]byte(markdownContent), nil, nil))
}

// 生成单个关键词的文章
func (ag *ArticleGenerator) GenerateForKeyword(keyword string, tagIds string, postsPerKeyword int, isPublish bool) ([]Article, error) {
	articles := make([]Article, 0)

	keyword = strings.TrimSpace(keyword)
	if keyword == "" {
		return articles, nil
	}

	fmt.Printf("\n处理关键词: %s\n", keyword)

	for i := 0; i < postsPerKeyword; i++ {
		fmt.Printf("生成第 %d/%d 篇文章...\n", i+1, postsPerKeyword)

		// 生成文章内容
		content, err := ag.generateContent(keyword, cast.ToInt(conf.GetConfig(conf.ArticleLength)), false)
		if err != nil {
			fmt.Printf("生成内容失败: %v\n", err)
			return articles, err
		}

		// 转换格式为html
		content = ag.markdownToHTML(content)

		// 读取第一行作为标题
		title := strings.Split(content, "\n")[0]
		// 移除h1标签
		title = strings.Replace(title, "<h1>", "", -1)
		title = strings.Replace(title, "</h1>", "", -1)
		// 移除第一行
		content = strings.Replace(content, title+"\n", "", 1)

		article := Article{
			Keywords: keyword,
			Content:  content,
			Title:    title,
			TagIds:   tagIds,
			Status:   0,
		}

		// 发布文章
		if isPublish {
			if err := ag.PublishArticle(article); err == nil {
				article.Status = 1
			}
		}
		articles = append(articles, article)

		log.Println("生成成功 title: ", title)
	}

	return articles, nil
}

// 批量生成并发布文章
func (ag *ArticleGenerator) GenerateAndPublish(keyword string, tagIds string, postsPerKeyword int, isPublish bool) map[int]Article {
	articles := make(map[int]Article, 0)

	keyword = strings.TrimSpace(keyword)
	if keyword == "" {
		return articles
	}

	fmt.Printf("\n处理关键词: %s\n", keyword)

	wg := sync.WaitGroup{}

	for i := 0; i < postsPerKeyword; i++ {
		wg.Add(1)
		fmt.Printf("生成第 %d/%d 篇文章...\n", i+1, postsPerKeyword)

		go func(i int) {
			defer wg.Done()
			// 生成文章内容
			content, err := ag.generateContent(keyword, cast.ToInt(conf.GetConfig(conf.ArticleLength)), false)
			if err != nil {
				fmt.Printf("生成内容失败: %v\n", err)
				return
			}

			// 转换格式为html
			content = ag.markdownToHTML(content)

			// 读取第一行作为标题
			title := strings.Split(content, "\n")[0]
			// 移除h1标签
			title = strings.Replace(title, "<h1>", "", -1)
			title = strings.Replace(title, "</h1>", "", -1)
			// 移除第一行
			content = strings.Replace(content, title+"\n", "", 1)

			// 创建或更新 Article 实例
			var article Article
			if existing, ok := articles[i]; ok {
				article = existing
			}
			article.Keywords = keyword
			article.Content = content
			article.Title = title
			article.TagIds = tagIds
			article.Status = 0

			// 发布文章
			if isPublish {
				if err := ag.PublishArticle(article); err == nil {
					article.Status = 1
				}
			}
			articles[i] = article

			log.Println("生成成功 title: ", title)
		}(i)

	}

	wg.Wait()

	return articles
}

func (ag *ArticleGenerator) PublishArticle(article Article) (err error) {
	url := config.Get("app.blog_api_url")
	method := "POST"

	payload := &bytes.Buffer{}
	writer := multipart.NewWriter(payload)
	_ = writer.WriteField("article_title", article.Title)
	if len(article.Category) > 0 {
		_ = writer.WriteField("category_id", article.Category)
	} else {
		_ = writer.WriteField("category_id", config.Get("app.blog_channel"))
	}
	_ = writer.WriteField("article_content", article.Content)
	_ = writer.WriteField("article_tags", "")
	_ = writer.WriteField("article_status", "1")
	_ = writer.WriteField("article_type", "1")
	_ = writer.WriteField("article_seo_title", article.Keywords)
	_ = writer.WriteField("article_seo_keywords", article.Keywords)
	_ = writer.WriteField("article_seo_description", article.Keywords)
	_ = writer.WriteField("article_name", article.Keywords)
	_ = writer.WriteField("article_excerpt", article.Keywords)
	_ = writer.WriteField("article_tags", fmt.Sprintf(`[%s]`, article.TagIds))
	err = writer.Close()
	if err != nil {
		return
	}

	client := &http.Client{}
	req, err := http.NewRequest(method, url, payload)

	if err != nil {
		return
	}
	req.Header.Add("Cookie", config.Get("app.blog_auth_token"))
	req.Header.Set("Content-Type", writer.FormDataContentType())
	res, err := client.Do(req)
	if err != nil {
		return
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return
	}

	var result map[string]interface{}
	err = json.Unmarshal(body, &result)
	if err != nil {
		return
	}
	if cast.ToInt(result["status"]) == 200 {
		log.Printf("文章发布成功: %s", article.Title)
	} else {
		log.Printf("文章发布失败，该文章在系统可能已经存在: %s，", article.Title)
		log.Println("msg:", result["msg"])
		return errors.New("文章发布失败")
	}

	return nil
}
